﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO.Ports;
using System.Windows.Forms;
using System.Configuration;
using CurrentCost.InputPlugin.Envir;
using OpenCost.Common;
using OpenCost.Common.Interfaces.Input;
using OpenCost.Common.Readings;
using OpenCost.OutputPlugin.XML;
using ZedGraph;

namespace OpenCost
{
    public partial class MainBody : Form
    {
        private IInput _ioHandler;
        private static PointPairList _ch1History;
        private static PointPairList _ch2History;
        private static PointPairList _ch3History;
        private static PointPairList _tempHistory;
        private static List<string> _subscribedOutputPlugins;

        public MainBody()
        {
            InitializeComponent();
            _subscribedOutputPlugins = new List<string>();
            _ioHandler = new Input();
            ConnectToggle();
            _ioHandler.NewReading += HandleLatestReading;
            tsLastTemp.Text = "--";
            tsLastReading.Text = "--";
            _ch1History = new PointPairList();
            _ch2History = new PointPairList();
            _ch3History = new PointPairList();
            _tempHistory = new PointPairList();
            CreateGraph(GraphRT);

            RefreshOutputPluginMenu();

        }

        private void CreateGraph(ZedGraphControl zpc)
        {
            GraphPane graphPane = zpc.GraphPane;
            graphPane.Title.Text = "Real Time Statistics";
            graphPane.Y2Axis.IsVisible = true;


            graphPane.XAxis.Title.Text = "Time";
            graphPane.YAxis.Title.Text = "Reading";
            graphPane.Y2Axis.Title.Text = "Temp";

            graphPane.XAxis.Type = AxisType.Date;
            graphPane.YAxis.Type = AxisType.Linear;
            graphPane.Y2Axis.Type = AxisType.Linear;

            LineItem curveItem = new LineItem("Temp") { IsY2Axis = true, Points = _tempHistory, Color = Color.Red };
            curveItem.MakeUnique();

            graphPane.AddCurve("Ch 1", _ch1History, Color.Green, SymbolType.Diamond);
            graphPane.AddCurve("Ch 2", _ch2History, Color.Blue, SymbolType.Circle);
            graphPane.AddCurve("Ch 3", _ch3History, Color.Yellow, SymbolType.Square);
            graphPane.CurveList.Add(curveItem);

            GraphRT.AxisChange();

        }


        private void HandleLatestReading(Reading Reading)
        {
            if (InvokeRequired)
            {
                Invoke(new Delegates.NewRealTimeReadingHandler(HandleLatestReading), Reading);
                return;
            }
            if (Reading.ReadingType == Enums.ReadingTypes.CurrentCostRealTime)
            {
                RealTimeReading _reading = (RealTimeReading) Reading;

                tsLastReading.Text = _reading.ch1 + " Watts";
                tsLastTemp.Text = _reading.temp.ToString() + '\u2103';
                tsDateTime.Text = "@ " + _reading.time;
                GraphPane graphPane = GraphRT.GraphPane;
                if (_reading.ch1 != 0.0)
                {
                    _ch1History.Add(new PointPair { X = _reading.time.ToOADate(), Y = double.Parse(_reading.ch1.ToString()) });
                }
                if (_reading.ch2 != 0.0)
                {
                    _ch2History.Add(new PointPair { X = _reading.time.ToOADate(), Y = double.Parse(_reading.ch2.ToString()) });
                }
                if (_reading.ch3 != 0.0)
                {
                    _ch3History.Add(new PointPair { X = _reading.time.ToOADate(), Y = double.Parse(_reading.ch3.ToString()) });
                }
                _tempHistory.Add(new PointPair { X = _reading.time.ToOADate(), Y = double.Parse(_reading.temp.ToString()) });
                graphPane.CurveList["Ch 1"].Points = _ch1History;
                graphPane.CurveList["Ch 2"].Points = _ch2History;
                graphPane.CurveList["Ch 3"].Points = _ch3History;
                graphPane.CurveList["Temp"].Points = _tempHistory;
                GraphRT.AxisChange();
                GraphRT.Refresh();
            }
        }



        private void btnConnect_Click(object sender, EventArgs e)
        {
            ConnectToggle();
        }
        private void ConnectToggle()
        {
            if (InvokeRequired)
            {
                ConnectToggle();
            }

            if (_ioHandler.serialPort == null)
            {
                btnConnect.Text = "Connect";
            }

            if (_ioHandler.serialPort != null && ((SerialPort) _ioHandler.serialPort).IsOpen)
            {
                ((SerialPort)_ioHandler.serialPort).Close();
                btnConnect.Text = "Connect";
                menuStrip1.Enabled = true;
            }
            else
            {
                if (Connect())
                {
                    btnConnect.Text = "Disconnect";
                    menuStrip1.Enabled = false;
                    return;
                }
                MessageBox.Show("Com port did not open. Try again");
            }
            menuStrip1.Enabled = true;
        }

        private bool Connect()
        {
            List<string> portNameList = new List<string>(SerialPort.GetPortNames());
            string savedComPort = ConfigurationManager.AppSettings["comPort"];
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            if (savedComPort != null && portNameList.Contains(savedComPort))
            {
                _ioHandler.createNewSerialPort(savedComPort);
            }
            else
            {
                switch (portNameList.Count)
                {
                    case 0:
                        MessageBox.Show(
                            "No com ports found on system. Check that device is connected, failing that check device manager for errors.",
                            "No Com Ports Found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        return false;
                    case 1:
                        if (savedComPort == null)
                        {
                            configuration.AppSettings.Settings.Add("comPort", portNameList[0]);
                        }
                        else
                        {
                            if (savedComPort != string.Empty)
                            {
                                if (MessageBox.Show(
                                        "Only one comport found on this machine and its different to the one thats saved/used last. Continue?",
                                        "Different com port found", MessageBoxButtons.YesNo, MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button1) == DialogResult.No)
                                {
                                    return false;
                                }

                            }
                            configuration.AppSettings.Settings["comPort"].Value = portNameList[0];
                        }
                        configuration.Save(ConfigurationSaveMode.Modified);
                        ConfigurationManager.RefreshSection("appSettings");
                        _ioHandler.createNewSerialPort(portNameList[0]);

                        break;

                    default:
                        MessageBox.Show(
                            "The com port that has been saved and used previously is no longer available. Either the device has changed port numbers or it is no longer connected. Please select a new one from the following List. If you are in any doubt look through device manager.");
                        comPortSelect comPortSelect = new comPortSelect(portNameList.ToArray());
                        if (comPortSelect.ShowDialog() == DialogResult.OK)
                        {
                            string selectedPort = comPortSelect.selectedPort;
                            ((SerialPort)_ioHandler.serialPort).PortName = selectedPort;
                            configuration.AppSettings.Settings["comPort"].Value = portNameList[0];
                            configuration.Save(ConfigurationSaveMode.Modified);
                            ConfigurationManager.RefreshSection("appSettings");
                        }
                        else
                        {
                            //user left the window without accepting new value
                            return false;
                        }
                        break;
                }
            }

            try
            {
                ((SerialPort)_ioHandler.serialPort).Open();

            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.ToString(), "Error Opening Com Port", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
                return false;
            }
            return ((SerialPort)_ioHandler.serialPort).IsOpen;

        }

        private void RefreshOutputPluginMenu()
        {
            if (InvokeRequired)
            {
                RefreshOutputPluginMenu();
            }

            ((ToolStripMenuItem)menuStrip1.Items[1]).DropDown.Items.Clear();

            foreach (OutputHost outputPlugin in PluginProvider.LoadedOutputPlugins)
            {
                ToolStripMenuItem item = new ToolStripMenuItem
                                             {
                                                 Text = outputPlugin.PluginTitle,
                                                 Checked = outputPlugin.isActive
                                             };
                item.Click+=OutputPluginClick;
                
                ToolStripMenuItem configItem = new ToolStripMenuItem{Text = outputPlugin.FormTitle};
                configItem.Click += ConfigItemClick;
                item.DropDown.Items.Add(configItem);
                item.DropDownDirection = ToolStripDropDownDirection.Right;
                ((ToolStripMenuItem)menuStrip1.Items[1]).DropDown.Items.Add(item);

            }

        }

        private static void ConfigItemClick(object sender, EventArgs e)
        {
            foreach (OutputHost plugin in PluginProvider.LoadedOutputPlugins)
            {
                if (plugin.PluginTitle == ((ToolStripItem)sender).OwnerItem.Text)
                {
                    plugin.Show();
                }  
            }
        }

        private void OutputPluginClick(object sender, EventArgs e)
        {
            PluginProvider.ToggleActivation(((ToolStripItem) sender).Text);
            ReattachOutputPluginEvents();
            RefreshOutputPluginMenu();
        }

        private void ReattachOutputPluginEvents()
        {
            foreach (OutputHost plugin in PluginProvider.LoadedOutputPlugins)
            {
                if (plugin.isActive)
                {
                    if (_subscribedOutputPlugins.IndexOf(plugin.PluginTitle) == -1)
                    {
                        _ioHandler.NewReading += plugin.SaveReading;
                        _subscribedOutputPlugins.Add(plugin.PluginTitle);
                    }
                }
                else
                {
                    _ioHandler.NewReading -= plugin.SaveReading;
                    _subscribedOutputPlugins.Remove(plugin.PluginTitle);
                }

            }
        }
    }
}
